Pipeline.isPipeFunction   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 9
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 9
c 0
b 0
f 0
rs 10
cc 1
1
import {Pipe, PipeFunction, PipeObject} from "./types/pipes";
2
3
export class Pipeline<T> {
4
    private passable: T | null = null;
5
    private pipes: Pipe<T>[] = [];
6
7
    /**
8
     * Set the object being sent through the pipeline.
9
     * @param passable The data to be passed through the pipeline.
10
     * @returns {Pipeline<T>} The pipeline instance.
11
     */
12
    send(passable: T): this {
13
        this.passable = passable;
14
        return this;
15
    }
16
17
    /**
18
     * Set the array of pipes.
19
     * @param pipes The pipes to process the passable object.
20
     * @returns {Pipeline<T>} The pipeline instance.
21
     */
22
    through(pipes: Pipe<T>[] | Pipe<T>): this {
23
        this.pipes = Array.isArray(pipes) ? pipes : [pipes];
24
        return this;
25
    }
26
27
    /**
28
     * Execute the pipeline and resolve the final result.
29
     * @param destination The final operation after all pipes.
30
     * @returns {Promise<T>} The final processed result.
31
     */
32
    async then(destination: (value: T) => Promise<T>): Promise<T> {
33
        if (this.passable === null) {
34
            throw new Error('No passable object provided to the pipeline.');
35
        }
36
37
        if (!this.pipes.length) {
38
            return destination(this.passable);
39
        }
40
41
        // Reduce the pipes into a single composed function, handling next internally
42
        const pipeline = this.pipes.reduceRight(
43
            (next: (value: T) => Promise<T>, pipe: Pipe<T>) => {
44
                return async (passable: T): Promise<T> => {
45
                    if (this.isPipeFunction(pipe)) {
46
                        const result = await pipe(passable);
47
                        return next(result);
48
                    }
49
                    if (this.isPipeObject(pipe)) {
50
                        const result = await pipe.handle(passable);
51
                        return next(result);
52
                    }
53
                    throw new Error('Pipe must be a function or an object with a "handle" method.');
54
                };
55
            },
56
            destination
57
        );
58
59
        return pipeline(this.passable);
60
    }
61
62
63
    /**
64
     * Type guard to check if the pipe is a function.
65
     * @param pipe The pipe to check.
66
     * @returns {pipe is PipeFunction<T>} Whether the pipe is a function.
67
     */
68
    private isPipeFunction(pipe: Pipe<T>): pipe is PipeFunction<T> {
69
        return typeof pipe === 'function';
70
    }
71
72
    /**
73
     * Type guard to check if the pipe is an object with a handle method.
74
     * @param pipe The pipe to check.
75
     * @returns {pipe is PipeObject<T>} Whether the pipe is an object with a handle method.
76
     */
77
    private isPipeObject(pipe: Pipe<T>): pipe is PipeObject<T> {
78
        return typeof (pipe as PipeObject<T>).handle === 'function';
79
    }
80
}
81